/*
 * @Author: liuzelin
 * @Date: 2023-09-09 09:49:05
 * @LastEditors: liuzelin
 * @LastEditTime: 2024-05-01 17:04:10
 * @Description: file content
 */
#pragma once

#include <functional>
#include <iostream>
#include <sstream>

#include "panda_export.hpp"

namespace Panda {
class PANDA_EXPORT LogHandler {
 public:
  enum LogLevel {
    Debug,
    Info,
    Warning,
    Error,
    Fatal,
    None,
  };

 public:
  static const char *LogLevelToStr(LogHandler::LogLevel l);
  static LogHandler &Instance();
  ~LogHandler() = default;
  void SetLogHandler(std::function<void(const char *)> &handler);
  void SetLogLevel(LogLevel l);
  void SetWriteFileName(bool w);
  void SetWriteFunction(bool w);
  void SetWriteLine(bool w);

 private:
  LogHandler();
  friend class LogItem;
  std::function<void(const char *)> handler;
  LogLevel level = LogLevel::Debug;
  bool writeFile = false;
  bool writeFunction = true;
  bool writeLine = true;
  bool writeLogLevel = false;
  bool writeThreadId = false;
  bool writeProcessId = false;
};

class PANDA_EXPORT LogItem {
 public:
  LogItem(LogHandler::LogLevel l, const char *file, const char *func,
          size_t line);
  ~LogItem();
  // template <class T>
  // LogItem &operator<<(T &&v)
  // {
  //     buff << v;
  //     return *this;
  // }

  template <class T>
  LogItem &operator<<(T *v) {
    buff << v;
    return *this;
  }

  template <class T>
  LogItem &operator<<(T v) {
    buff << v;
    return *this;
  }

  LogItem &operator<<(bool v) {
    buff << (v ? "true" : "false");
    return *this;
  }

 private:
  std::stringstream buff;
  LogHandler::LogLevel level;
};

#define LOG(l) \
  Panda::LogItem(Panda::LogHandler::l, __FILE__, __FUNCTION__, __LINE__)

#define PandaCheck(condition) \
  if (!(condition)) LOG(Fatal) << #condition << " "
}  // namespace Panda